home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / WASTE 1.2a4 / WASTE Demo / WEDemoWindows.c < prev   
Encoding:
C/C++ Source or Header  |  1995-11-05  |  24.4 KB  |  1,168 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     Window Handling
  4.             
  5.     Copyright © 1993-1995 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __ALIASES__
  13. #include <Aliases.h>
  14. #endif
  15.  
  16. #ifndef __TOOLUTILS__
  17. #include <ToolUtils.h>
  18. #endif
  19.  
  20. #ifndef _LongCoords_
  21. #include "LongCoords.h"
  22. #endif
  23.  
  24. #ifndef __WEDEMOAPP__
  25. #include "WEDemoIntf.h"
  26. #endif
  27.  
  28. // some consts used by DoGrow()
  29.  
  30. enum {
  31.     kMinWindowWidth        = 200,
  32.     kMinWindowHeight    = 80
  33. };
  34.  
  35. // static variables
  36.  
  37. static WEScrollUPP            sWEScroller;
  38. static WETranslateDragUPP    sWEDragTranslator;
  39. static ControlActionUPP        sScrollProc;
  40. static short                sScrollStep; // how many pixels to scroll (used by ScrollProc)
  41.  
  42.  
  43. static void    CalcGrowIconRect( WindowRef window, Rect *iconRect )
  44. {
  45.     Rect portRect = GetWindowPort( window )->portRect;
  46.     
  47.     iconRect->top = portRect.bottom - (kBarWidth - 2);
  48.     iconRect->left = portRect.right - (kBarWidth - 2);
  49.     iconRect->bottom = portRect.bottom;
  50.     iconRect->right = portRect.right;
  51. }
  52.  
  53. static void    CalcTextRect( WindowRef window, Rect *textRect )
  54. {
  55.     Rect portRect = GetWindowPort( window )->portRect;
  56.     
  57.     textRect->top = 0;
  58.     textRect->left = 0;
  59.     textRect->bottom = portRect.bottom - (kBarWidth - 1);
  60.     textRect->right = portRect.right - (kBarWidth - 1);
  61.     InsetRect( textRect, kTextMargin, kTextMargin );
  62. }
  63.  
  64. static void    CalcScrollBarRect( WindowRef window, VHSelect axis, Rect *barRect )
  65. {
  66.     Rect portRect = GetWindowPort( window )->portRect;
  67.     
  68.     switch ( axis )
  69.     {
  70.         case v:
  71.             barRect->top = -1;
  72.             barRect->left = portRect.right - (kBarWidth - 1);
  73.             barRect->bottom = portRect.bottom - (kBarWidth - 2);
  74.             barRect->right = portRect.right + 1;
  75.             break;
  76.  
  77.         case h:
  78.             barRect->top = portRect.bottom - (kBarWidth - 1);
  79.             barRect->left = -1;
  80.             barRect->bottom = portRect.bottom + 1;
  81.             barRect->right = portRect.right - (kBarWidth - 2 );
  82.             break;
  83.         
  84.         default:
  85.             break;
  86.     }
  87. }
  88.  
  89. /*
  90.     the standard Toolbox trap _DrawGrowIcon draws two lines from the grow icon
  91.     to the left and top margins of the window's content area
  92.     these additional lines may create ugly dirt, so we use this routine to temporarily
  93.     set the clip region to the grow icon rect.
  94.     
  95.     in addition, if validate is true, we call _ValidRect on the icon rect
  96. */
  97.  
  98. static void    MyDrawGrowIcon( WindowRef window, Boolean validate )
  99. {
  100.     GrafPtr        savePort;
  101.     RgnHandle    saveClip;
  102.     Rect        r;
  103.     
  104.     // save port and set thePort to wind
  105.     
  106.     GetPort( &savePort );
  107.     SetPortWindowPort( window );
  108.     
  109.     // save the clip region
  110.     
  111.     saveClip = NewRgn();
  112.     GetClip( saveClip );
  113.     
  114.     // calculate the grow icon rect
  115.     
  116.     CalcGrowIconRect( window, &r );
  117.     
  118.     // set clip region to grow icon rect
  119.     
  120.     ClipRect( &r );
  121.     
  122.     // call _DrawGrowIcon
  123.     
  124.     DrawGrowIcon( window );
  125.     
  126.     // if validate is true, remove the grow icon rect from the update region
  127.     
  128.     if ( validate )
  129.         ValidRect( &r );
  130.     
  131.     // restore old clip region
  132.     
  133.     SetClip( saveClip );
  134.     DisposeRgn( saveClip );
  135.     
  136.     // restore old port
  137.     
  138.     SetPort( savePort );
  139.     
  140.     return;
  141. }
  142.  
  143. static void    ScrollBarChanged( WindowRef window )
  144. {
  145.     // scroll text to reflect new scroll bar setting
  146.  
  147.     WEReference    we;
  148.     LongRect    viewRect, destRect;
  149.     
  150.     we = GetWindowWE(window);
  151.     WEGetViewRect( &viewRect, we );
  152.     WEGetDestRect( &destRect, we );
  153.     WEScroll( viewRect.left - destRect.left - LCGetValue( ((* GetWindowDocument(window))->scrollBars).h), 
  154.         viewRect.top - destRect.top - LCGetValue( ((* GetWindowDocument(window))->scrollBars).v), we );
  155.     
  156.     return;
  157. }
  158.  
  159. static void    AdjustBars( WindowRef window )
  160. {
  161.     DocumentHandle    hDocument;
  162.     WEReference        we;
  163.     GrafPtr            savePort;
  164.     LongRect        viewRect, destRect;
  165.     long            value;
  166.     long            max;
  167.     ControlRef        bar;
  168.     
  169.     GetPort( &savePort );
  170.     SetPortWindowPort( window );
  171.     
  172.     hDocument = GetWindowDocument(window);
  173.     we = (*hDocument)->we;
  174.     
  175.     // get the view and destination rectangle
  176.     
  177.     WEGetViewRect( &viewRect, we );
  178.     WEGetDestRect( &destRect, we );
  179.         
  180.     //    do the vertical axis
  181.     
  182.     //    get scroll bar handle
  183.     
  184.     bar = ((*hDocument)->scrollBars).v;
  185.     
  186.     //    calculate new scroll bar settings
  187.     
  188.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  189.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  190.     
  191.     value = viewRect.top - destRect.top;
  192.     
  193.     max = value + (destRect.bottom - viewRect.bottom);
  194.     
  195.     //    make sure max is always non-negative
  196.     
  197.     if ( max <= 0 )
  198.         max = 0;
  199.         
  200.     //    reset the scroll bar
  201.     
  202.     LCSetMax( bar, max );
  203.     LCSetValue( bar, value );
  204.     
  205.     //    if value exceeds max then the bottom of the destRect is above
  206.     //    the bottom of the view rectangle:  we need to scroll the text downward
  207.     
  208.     if ( value > max )
  209.         ScrollBarChanged( window );
  210.     
  211.     //    now do the horizontal axis
  212.     
  213.         //    get scroll bar handle
  214.     
  215.     bar = ((*hDocument)->scrollBars).h;
  216.     
  217.     //    calculate new scroll bar settings
  218.     
  219.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  220.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  221.     
  222.     value = viewRect.left - destRect.left;    
  223.     
  224.     max = value + (destRect.right - viewRect.right);
  225.     
  226.     //    make sure max is always non-negative
  227.     
  228.     if ( max <= 0 )
  229.         max = 0;
  230.         
  231.     //    reset the scroll bar
  232.     
  233.     LCSetMax( bar, max );
  234.     LCSetValue( bar, value );
  235.     
  236.     //    if value exceeds max then the bottom of the destRect is above
  237.     //    the bottom of the view rectangle:  we need to scroll the text downward
  238.     
  239.     if ( value > max )
  240.         ScrollBarChanged( window );
  241.     
  242.     SetPort( savePort );
  243.     
  244.     return;
  245. }
  246.  
  247.  
  248. static void    ViewChanged( WindowRef window )
  249. {
  250.     DocumentHandle    hDocument;
  251.     GrafPtr            savePort;
  252.     ControlRef        bar;
  253.     Rect            r;
  254.     LongRect        viewRect;
  255.     
  256.     GetPort( &savePort );
  257.     SetPortWindowPort( window );
  258.     
  259.     hDocument = GetWindowDocument( window );
  260.     
  261.     //    resize the text area
  262.     
  263.     CalcTextRect( window, &r );
  264.     WERectToLongRect( &r, &viewRect );
  265.     WESetViewRect( &viewRect, (*hDocument)->we );
  266.     
  267.     //     move and resize the control bars
  268.     //    first, the vertical bar
  269.     
  270.     bar = ((*hDocument)->scrollBars).v;
  271.     CalcScrollBarRect( window, v, &r );
  272.     MoveControl( bar, r.left, r.top );
  273.     SizeControl( bar, r.right - r.left, r.bottom - r.top );
  274.     ValidRect( &r );
  275.     
  276.     //    now the horizontal bar
  277.     
  278.     bar = ((*hDocument)->scrollBars).h;
  279.     CalcScrollBarRect( window, h, &r );
  280.     MoveControl( bar, r.left, r.top );
  281.     SizeControl( bar, r.right - r.left, r.bottom - r.top );
  282.     ValidRect( &r );
  283.     
  284.     //    reset the thumb positions and the max values of the control bars
  285.     AdjustBars( window );
  286.     
  287.     //    redraw the control bars
  288.     ShowControl( ((*hDocument)->scrollBars).v );
  289.     ShowControl( ((*hDocument)->scrollBars).h );
  290.     
  291.     SetPort( savePort );
  292.     
  293.     return;
  294. }
  295.  
  296. /*
  297.     This is a deviation from the original Pascal WASTE Demo App code.
  298.     
  299.     This "morally correct" code for window dragging is per an article in MacTech
  300.     Magazine (July 1994, Vol 10, No. 7). by Eric Shapiro (of Rock Ridge Enterprises)
  301.     called "Multiple Monitors vs. Your Application"
  302.     
  303.     Eric addressed numerous things to allow your app to deal nicely with multiple
  304.     monitor setups, one of them is dragging.
  305.     
  306.     According to Eric, many apps don't let you drag windows to second monitors, and
  307.     though holding down the cmd/opt keys often overrides this problem, it should
  308.     still be updated.  And the only reason qd.screenBits.bounds works to allow
  309.     you to drag to second monitors is because of a kludge Apple put in the Window Manager
  310.     
  311.     So, this is some code from Eric to make our app be "morally correct" :)
  312. */
  313.  
  314. void    DoDrag( Point thePoint, WindowRef window )
  315. {
  316.     Rect        limitR;
  317.  
  318.     if ( gHasColorQD )
  319.         limitR = ( **GetGrayRgn()).rgnBBox;
  320.     else
  321.         limitR = qd.screenBits.bounds;
  322.                         
  323.     DragWindow( window, thePoint, &limitR );
  324.  
  325.     return;
  326. }
  327.  
  328.  
  329. void    Resize( Point newSize, WindowRef window )
  330. {
  331.     DocumentHandle    hDocument;
  332.     GrafPtr            savePort;
  333.     Rect            r;
  334.     RgnHandle        tempRgn, dirtyRgn;
  335.     
  336.     GetPort( &savePort );
  337.     SetPortWindowPort( window );
  338.     
  339.     hDocument = GetWindowDocument( window );
  340.     
  341.     //    create temporarty regions for calculations
  342.     tempRgn = NewRgn();
  343.     dirtyRgn = NewRgn();
  344.     
  345.     //    save old text region
  346.     
  347.     CalcTextRect( window, &r );
  348.     RectRgn( tempRgn, &r );
  349.         
  350.     //    erase the old grow icon rect
  351.     CalcGrowIconRect( window, &r );
  352.     EraseRect( &r );
  353.     
  354.     //    hide the scroll bars
  355.     
  356.     HideControl( ((*hDocument)->scrollBars).v );
  357.     HideControl( ((*hDocument)->scrollBars).h );
  358.     
  359.     //    perform the actual resizing of the window, redraw scroll bars and grow icon
  360.     SizeWindow( window, newSize.h, newSize.v, false );
  361.     ViewChanged( window );
  362.     MyDrawGrowIcon( window, true );
  363.     
  364.     //    calculate the dirty region (to be updated)
  365.     CalcTextRect( window, &r );
  366.     RectRgn( dirtyRgn, &r );
  367.     XorRgn( dirtyRgn, tempRgn, dirtyRgn );
  368.     InsetRect( &r, -kTextMargin, -kTextMargin );
  369.     RectRgn( tempRgn, &r );
  370.     SectRgn( dirtyRgn, tempRgn, dirtyRgn );
  371.     
  372.     //    mark the dirty region as invalid
  373.     InvalRgn( dirtyRgn );
  374.     
  375.     //    throw away temporary regions
  376.     DisposeRgn( tempRgn );
  377.     DisposeRgn( dirtyRgn );
  378.     
  379.     SetPort( savePort );
  380.     
  381.     return;
  382. }
  383.  
  384. void    DoGrow( Point hitPt, WindowRef window )
  385. {
  386.     Rect        sizeRect;
  387.     long        newSize;
  388.     Point        tempPoint;
  389.     
  390.     SetRect( &sizeRect, kMinWindowWidth, kMinWindowHeight, SHRT_MAX, SHRT_MAX );
  391.     newSize = GrowWindow( window, hitPt, &sizeRect );
  392.     
  393.     //    In the WASTE Demo App source, Marco typecasted newSize to a type Point.  Can't
  394.     //    do that in C (but you can, obviously, in Pascal).    
  395.     //    But there is a trick!  The Point structure is 32-bits, with the v value
  396.     //    in the hi word and the h value in the low word.  So, we can just separate
  397.     //    them out.  Neat huh?
  398.             
  399.     if ( newSize != 0 )
  400.     {
  401.         tempPoint.v = HiWrd( newSize );
  402.         tempPoint.h = LoWrd( newSize );
  403.         
  404.         Resize( tempPoint, window );
  405.     }
  406.     return;
  407. }
  408.  
  409.  
  410. void    DoZoom( short partCode, WindowRef window )
  411. {
  412.     DocumentHandle    hDocument;
  413.     GrafPtr            savePort;
  414.     Rect            r;
  415.     
  416.     GetPort( &savePort );
  417.     SetPortWindowPort( window );
  418.     
  419.     hDocument = GetWindowDocument(window);
  420.     
  421.     r = GetWindowPort( window )->portRect;
  422.     EraseRect( &r );
  423.     HideControl( ((*hDocument)->scrollBars).v );
  424.     HideControl( ((*hDocument)->scrollBars).h );
  425.     
  426.     ZoomWindow( window, partCode, false );
  427.     
  428.     ViewChanged( window );
  429.     CalcTextRect( window, &r );
  430.     InvalRect( &r );
  431.     
  432.     SetPort( savePort );
  433.     
  434.     return;
  435. }
  436.  
  437. // this is a callback tourine called by the Toolbox Control Manager
  438. // move the scroll bar thumb and scroll the text accordingly
  439.  
  440. static pascal void ScrollProc( ControlRef bar, ControlPartCode partCode )
  441. {
  442.     long        value, step;
  443.  
  444.     if ( partCode == kControlNoPart )
  445.         return;
  446.     
  447.     value = LCGetValue( bar );
  448.     step = sScrollStep;
  449.  
  450.     if ( (( value < LCGetMax( bar )) && ( step > 0 )) || (( value > 0 ) && ( step < 0 ) ) )
  451.     {
  452.         LCSetValue( bar, value + step );
  453.         ScrollBarChanged( FrontWindow() );
  454.     }
  455.  
  456.     return;
  457. }
  458.  
  459. static void    DoScrollBar( Point hitPt, EventModifiers modifiers, WindowRef window )
  460. {
  461.     DocumentHandle        hDocument;
  462.     ControlRef            bar;
  463.     LongRect            viewRect;
  464.     ControlPartCode        partCode;
  465.     short                step;
  466.     
  467.     hDocument = GetWindowDocument(window);
  468.     WEGetViewRect( &viewRect, (*hDocument)->we );
  469.  
  470.     //    find out which scrollbar was hit (if any) and in which part
  471.     partCode = FindControl( hitPt, window, &bar );
  472.     
  473.     if ( bar != NULL )
  474.     {
  475.         //    dispatch on partCode
  476.     
  477.         if ( partCode == kControlIndicatorPart )
  478.         {
  479.             // click in thumb: call TrackControl with no actionProc and adjust text
  480.             
  481.             partCode = TrackControl( bar, hitPt, NULL );
  482.             LCSynch( bar );
  483.             ScrollBarChanged( window );
  484.             
  485.         } // end if partCode == kControlIndicatorPart
  486.     
  487.         else
  488.  
  489.         {
  490.             if ( bar == ((*hDocument)->scrollBars).v )
  491.             {
  492.             
  493.                 // dispatch our partCode
  494.             
  495.                 switch( partCode )
  496.                 {
  497.                     case kControlUpButtonPart:
  498.                         if ( (modifiers & optionKey ) == 0 )
  499.                             step = -kScrollDelta;
  500.                         else
  501.                             step = -1;
  502.                 
  503.                     break;
  504.                 
  505.                     case kControlDownButtonPart:
  506.                         if ( (modifiers & optionKey ) == 0 )
  507.                             step = +kScrollDelta;
  508.                         else
  509.                             step = 1;
  510.                 
  511.                     break;
  512.                 
  513.                     case kControlPageUpPart:
  514.                         step = -( viewRect.bottom - viewRect.top) + kScrollDelta;
  515.             
  516.                     break;
  517.                 
  518.                     case kControlPageDownPart:
  519.                         step = ( viewRect.bottom - viewRect.top ) - kScrollDelta;
  520.             
  521.                     break;
  522.                 
  523.                     default:
  524.                         step = 0;
  525.                 }
  526.             }
  527.             else if ( bar == ((*hDocument)->scrollBars).h )
  528.             {
  529.             
  530.                 // dispatch our partCode
  531.             
  532.                 switch( partCode )
  533.                 {
  534.                     case kControlUpButtonPart:
  535.                         if ( (modifiers & optionKey ) == 0 )
  536.                             step = -kScrollDelta;
  537.                         else
  538.                             step = -1;
  539.                 
  540.                     break;
  541.                 
  542.                     case kControlDownButtonPart:
  543.                         if ( (modifiers & optionKey ) == 0 )
  544.                             step = +kScrollDelta;
  545.                         else
  546.                             step = 1;
  547.                 
  548.                     break;
  549.                 
  550.                     case kControlPageUpPart:
  551.                         step = -( viewRect.right - viewRect.left) + kScrollDelta;
  552.             
  553.                     break;
  554.                 
  555.                     case kControlPageDownPart:
  556.                         step = ( viewRect.right - viewRect.left ) - kScrollDelta;
  557.             
  558.                     break;
  559.                 
  560.                     default:
  561.                         step = 0;
  562.                 }
  563.             }
  564.     
  565.             //    save step in a static variable for our ScrollProc callback
  566.         
  567.             sScrollStep = step;
  568.         
  569.             //    track the mouse
  570.         
  571.             if ( sScrollProc == NULL )
  572.                 sScrollProc = NewControlActionProc( ScrollProc );
  573.             partCode = TrackControl( bar, hitPt, sScrollProc );
  574.         }
  575.  
  576.     }
  577.     
  578.     return;
  579. }
  580.  
  581.  
  582. /*
  583.     This is a callback routine called whenever the text is scrolled automaticall.
  584.     Since auto-scrolling is enabled, WEScroll may be invoked internally by WASTE
  585.     in many different circumstances, and we want to be notified when this happens
  586.     so we can adjust the scroll bars
  587. */
  588.  
  589. static pascal void TextScrolled( WEReference we )
  590. {
  591.     WindowRef        window = NULL;
  592.     
  593.     //    retrieve the window pointer stored in the WE instance as a "reference constant"
  594.     
  595.     if (WEGetInfo(weRefCon, &window, we) != noErr )
  596.         return;
  597.     
  598.     //    make sure the scroll bars are in synch with the destination rectangle
  599.     
  600.     AdjustBars( window );
  601.  
  602.     return;
  603. }
  604.  
  605.  
  606. Boolean    DoContent( Point hitPt, const EventRecord *event, WindowRef window )
  607. {
  608.     WEReference        we;
  609.     Boolean            inBackground, handleClick;
  610.     Rect            textRect;
  611.     GrafPtr            savePort;
  612.     Boolean            result = false; // false means click should not activate this window
  613.     
  614.     we = GetWindowWE(window);
  615.     
  616.     //    is this windowd in the background?
  617.     
  618.     if ( IsWindowHilited( window ) )
  619.         inBackground = false;
  620.     else
  621.         inBackground = true;
  622.  
  623.     
  624.     //    set the port to our window's port
  625.     
  626.     GetPort( &savePort );
  627.     SetPortWindowPort( window );
  628.     
  629.     //    convert the point to local coordinates
  630.     
  631.     GlobalToLocal( &hitPt );
  632.     
  633.     //    a click in an inactive window should normally activate it,
  634.     //    but the availability of the Drag Manager introduces an exception to this rule:
  635.     //    a click in the background selection may start a drag gesture,
  636.     //    without activating the window
  637.     
  638.     if ( inBackground )
  639.     {
  640.         if ( gHasDragAndDrop )
  641.         {
  642.             long selStart, selEnd;
  643.             RgnHandle selRgn;
  644.  
  645.             WEGetSelection( &selStart, &selEnd, we );
  646.             selRgn = WEGetHiliteRgn( selStart, selEnd, we );
  647.             handleClick = PtInRgn( hitPt, selRgn ) && WaitMouseMoved( event->where );
  648.             DisposeRgn( selRgn );
  649.         }
  650.         else
  651.             handleClick = false; // no DragManager: never click-through
  652.     }
  653.     else
  654.         handleClick = true;    // window is frontmost: always handle click
  655.         
  656.     if ( handleClick )
  657.     {
  658.         CalcTextRect( window, &textRect );
  659.         
  660.         if ( PtInRect( hitPt, &textRect ) )
  661.             WEClick( hitPt, event->modifiers, event->when, we );
  662.         else
  663.             DoScrollBar( hitPt, event->modifiers, window );
  664.     }
  665.     else
  666.         result = inBackground;
  667.     
  668.     //    restore the port
  669.     
  670.     SetPort( savePort );
  671.     
  672.     
  673.     return result;
  674. }
  675.  
  676.  
  677. static void    DoScrollKey( SignedByte keyCode, WindowRef window )
  678. {
  679.     DocumentHandle        hDocument;
  680.     ControlRef            bar;
  681.     long                v;
  682.     LongRect            viewRect;
  683.     
  684.     hDocument = GetWindowDocument(window);
  685.     bar = ((*hDocument)->scrollBars).v;
  686.  
  687.     //    get current scroll bar value
  688.     
  689.     v = LCGetValue( bar );
  690.     
  691.     //    get text view rect
  692.     
  693.     WEGetViewRect( &viewRect, (*hDocument)->we );
  694.     
  695.     switch ( keyCode )
  696.     {
  697.     
  698.         case keyPgUp:
  699.             v -= ( viewRect.bottom - viewRect.top ) + kScrollDelta;        
  700.             break;
  701.         
  702.         case keyPgDn:
  703.             v += ( viewRect.bottom - viewRect.top ) - kScrollDelta;
  704.             break;
  705.  
  706.         case keyHome:
  707.             v = 0;
  708.             break;
  709.         
  710.         case keyEnd:
  711.             v = LONG_MAX;
  712.             break;
  713.         
  714.         default:
  715.             break;
  716.     }    // end switch keyCode
  717.     
  718.     
  719.     //    set the new scroll bar value and scroll the text pane accordingly
  720.     
  721.     LCSetValue( bar, v );
  722.     ScrollBarChanged( window );
  723.     
  724.     return;
  725. }    
  726.  
  727.  
  728. void    DoKey( char key, const EventRecord *event )
  729. {
  730.     WindowRef        window;
  731.     SignedByte        keyCode;
  732.     
  733.     window = FrontWindow();
  734.     
  735.     //    do nothing if no window is active
  736.     
  737.     if ( window == NULL )
  738.         return;
  739.     
  740.     //    extract virtual key code from event record
  741.     
  742. //    keyCode = ( event->message & keyCodeMask ) >> 8;
  743.     keyCode = BSR( BAND(event->message, keyCodeMask ), 8 );
  744.         
  745.     // page movement keys are handled by HsoiDoScrollKey()
  746.     
  747.     switch ( keyCode )
  748.     {
  749.         case keyPgUp:
  750.         case keyPgDn:
  751.         case keyHome:
  752.         case keyEnd:
  753.             DoScrollKey( keyCode, window );
  754.         break;
  755.         
  756.         default:
  757.             WEKey( key, event->modifiers, GetWindowWE(window) );
  758.         break;
  759.     }
  760.     
  761.     return;
  762. }
  763.  
  764. void    DoUpdate( WindowRef window )
  765. {
  766.     GrafPtr        savePort;
  767.     RgnHandle    updateRgn;
  768.     
  769.     // if we have no windows, there's nothing to update!
  770.  
  771.     if ( window == NULL )
  772.         return;
  773.     
  774.     // save the old drawing port
  775.     
  776.     GetPort( &savePort );
  777.     SetPortWindowPort( window );
  778.     
  779.     // notify everything that we're doing an update.
  780.     
  781.     BeginUpdate( window );
  782.     
  783.     // BeginUpdate sets the window port visRgn to the region to update
  784.     
  785.     updateRgn = GetWindowPort(window)->visRgn;
  786.     
  787.     if ( !EmptyRgn( updateRgn ) )    // if it's not an empty region, let's update it!
  788.     {
  789.  
  790.         // erase the update region
  791.         EraseRgn( updateRgn );
  792.  
  793.         //    draw scroll bars
  794.         UpdateControls( window, updateRgn );
  795.         
  796.         //    draw grow icon
  797.         MyDrawGrowIcon( window, false );
  798.         
  799.         //    draw text
  800.         WEUpdate( updateRgn, GetWindowWE( window ) );
  801.  
  802.     }
  803.  
  804.     // tell everything we're done updating
  805.     
  806.     EndUpdate( window );
  807.     
  808.     // restore the old graphics port
  809.     
  810.     SetPort( savePort );
  811.     
  812.     
  813.     return;
  814. }
  815.  
  816.  
  817. void    DoActivate( Boolean activFlag, WindowRef window )
  818. {
  819.     DocumentHandle        hDocument;
  820.     WEReference            we;
  821.     GrafPtr                savePort;
  822.     ControlPartCode        barHilite;
  823.     Rect                barRect;
  824.     short                menuID;
  825.     
  826.     // if there aren't any windows, nothing to do here...
  827.  
  828.     if (window == NULL)
  829.         return;
  830.     
  831.     hDocument = GetWindowDocument(window);
  832.     we = (*hDocument)->we;
  833.             
  834.     //     set up the port
  835.     
  836.     GetPort( &savePort );
  837.     SetPortWindowPort( window );
  838.  
  839.     // activate or deactivate the text (and any other relevant stuff) depending on just
  840.     // what we're doing here...
  841.     
  842.  
  843.     if ( activFlag )
  844.     {
  845.         WEActivate( we );
  846.         barHilite = kControlNoPart;
  847.     }
  848.     else
  849.     {
  850.         WEDeactivate( we );
  851.         barHilite = kControlDisabledPart;
  852.     }
  853.     
  854.     
  855.     //    redraw the grow icon (and validate it's rect)
  856.     
  857.     MyDrawGrowIcon( window, true );
  858.     
  859.     //    redraw the scroll bars with the new highlighting (and validate their rects)
  860.     //    first, the vertical scroll bar
  861.     
  862.     HiliteControl( ((*hDocument)->scrollBars).v, barHilite );
  863.     CalcScrollBarRect( window, v, &barRect );
  864.     ValidRect( &barRect );
  865.     
  866.     //    now the horizontal scroll bar
  867.  
  868.     HiliteControl( ((*hDocument)->scrollBars).h, barHilite );
  869.     CalcScrollBarRect( window, h, &barRect );
  870.     ValidRect( &barRect );
  871.  
  872.     //    dim or undim text-related menus
  873.  
  874.     for ( menuID = kMenuEdit; menuID <= kMenuFeatures; menuID++ )
  875.     {
  876.         if ( activeFlag )
  877.             EnableItem( GetMenuHandle( menuID ), 0 );
  878.         else
  879.             DisableItem( GetMenuHandle( menuID ), 0 );
  880.     }
  881.     
  882.     // invalidate the menu bar
  883.     
  884.     InvalMenuBar();
  885.     
  886.     // restore the old graphics port..
  887.     
  888.     SetPort( savePort );
  889.     
  890.     return;
  891. }
  892.  
  893. OSErr    CreateWindow( const FSSpec *pFileSpec )
  894. {
  895.     DocumentHandle    hDocument;
  896.     WindowRef        window;
  897.     WEReference        we;
  898.     ControlRef        bar;
  899.     FInfo            fileInfo;
  900.     Rect            textRect;
  901.     LongRect        longTextRect;
  902.     OSErr            err = noErr;
  903.     AliasHandle        alHandle;
  904.  
  905.     
  906.     //    allocate a relocateable block to hold a document record
  907.     
  908.     hDocument = (DocumentHandle) NewHandleClear( sizeof( DocumentRecord ) );
  909.     err = MemError();
  910.     if ( err != noErr )
  911.     {
  912.         ErrorAlert( err );
  913.         return err;
  914.     }
  915.  
  916.     //    create the window from a 'WIND' template: the window is initially invisible
  917.     //    if ColorQuickDraw is available, create a color window
  918.     
  919.     if ( gHasColorQD )
  920.         window = GetNewCWindow( kWindowTemplateID, NULL, (WindowRef) -1L );
  921.     else
  922.         window = GetNewWindow( kWindowTemplateID, NULL, (WindowRef) -1L );
  923.     
  924.     //    make sure we got a window
  925.     
  926.     if ( window == NULL )
  927.     {
  928.         err = memFullErr;
  929.         ErrorAlert( err );
  930.         return err;
  931.     }
  932.     
  933.     // link the document record to the window and the other way around
  934.     
  935.     SetWRefCon(window, (long) hDocument);
  936.     (*hDocument)->owner = window;
  937.  
  938.     // we got a window, so tell QuickDraw where to draw...
  939.     
  940.     SetPortWindowPort( window );
  941.             
  942.     //    calculate the text rectangle
  943.     
  944.     CalcTextRect( window, &textRect );
  945.     WERectToLongRect( &textRect, &longTextRect );    
  946.     
  947.     //    create new WASTE instance
  948.     err = WENew( &longTextRect, &longTextRect, weDoAutoScroll + 
  949.                                                weDoOutlineHilite +
  950.                                                weDoUndo +
  951.                                                weDoIntCutAndPaste +
  952.                                                weDoDragAndDrop +
  953.                                                weDoUseTempMem +
  954.                                                weDoDrawOffscreen, &we);
  955.     
  956.     if ( err != noErr )
  957.     {
  958.         ErrorAlert( err );
  959.         return err;
  960.     }
  961.  
  962.     // set the alignment to weFlushLeft so "slop recalc" is disabled
  963.     
  964.     WESetAlignment( weFlushLeft, we );
  965.         
  966.  
  967.     //    save a reference to the window in the WE instance
  968.     err = WESetInfo( weRefCon, &window, we );
  969.     if ( err != noErr )
  970.     {
  971.         ErrorAlert( err );
  972.         return err;
  973.     }
  974.     
  975.     //    now the other way around:  save the WE reference in the document record
  976.     
  977.     (*hDocument)->we = we;
  978.     
  979.     // create routine descriptors for the WASTE callbacks
  980.     
  981.     if ( sWEScroller == NULL )
  982.     {
  983.         sWEScroller = NewWEScrollProc( TextScrolled );
  984.         sWEDragTranslator = NewWETranslateDragProc( TranslateDrag );
  985.     }
  986.     
  987.     //    set up our callbacks
  988.     
  989.     err = WESetInfo( weScrollProc, &sWEScroller, we );
  990.     if ( err != noErr )
  991.     {
  992.         ErrorAlert( err );
  993.         return err;
  994.     }
  995.  
  996.     err = WESetInfo( weTranslateDragHook, &sWEDragTranslator, we );
  997.     if ( err != noErr )
  998.     {
  999.         ErrorAlert( err );
  1000.         return err;
  1001.     }
  1002.     
  1003.     //    create a scroll bar from a 'CNTL' template
  1004.     
  1005.     //    first vertical
  1006.     
  1007.     bar = GetNewControl( kScrollBarTemplateID, window );
  1008.     if ( bar == NULL )
  1009.     {
  1010.         err = memFullErr;
  1011.         ErrorAlert( err );
  1012.         return err;
  1013.     }
  1014.     
  1015.     HiliteControl( bar, kControlDisabledPart );
  1016.     
  1017.     //    attach a LongControl record to the scroll bar:  this allows us to use long
  1018.     //    settings and thus scroll text taller than 32,767 pixels
  1019.     
  1020.     err = LCAttach( bar );
  1021.     if ( err != noErr )
  1022.     {
  1023.         ErrorAlert( err );
  1024.         return err;
  1025.     }
  1026.     
  1027.     //    save control handle in the document record
  1028.     
  1029.     ((*hDocument)->scrollBars).v = bar;    
  1030.     
  1031.     //    now horizontal
  1032.     
  1033.     bar = GetNewControl( kScrollBarTemplateID, window );
  1034.     if ( bar == NULL )
  1035.     {
  1036.         err = memFullErr;
  1037.         ErrorAlert( err );
  1038.         return err;
  1039.     }
  1040.     
  1041.     HiliteControl( bar, kControlDisabledPart );
  1042.     
  1043.     //    attach a LongControl record to the scroll bar:  this allows us to use long
  1044.     //    settings and thus scroll text taller than 32,767 pixels
  1045.     
  1046.     err = LCAttach( bar );
  1047.     if ( err != noErr )
  1048.     {
  1049.         ErrorAlert( err );
  1050.         return err;
  1051.     }
  1052.     
  1053.     //    save control handle in the document record
  1054.     
  1055.     ((*hDocument)->scrollBars).h = bar;    
  1056.     
  1057.     //    ViewChanged() adjusts the scroll bars rectangles to the window frame
  1058.     
  1059.     ViewChanged( window );
  1060.     
  1061.     //    if pFileSpec is not NULL, it points to a file to read, so let's read it!
  1062.     
  1063.     if ( pFileSpec != NULL )
  1064.     {
  1065.         // turn the cursor into a wristwatch because this can be a lengthy operation
  1066.         
  1067.         SetCursor( *(GetCursor(watchCursor)) );
  1068.         
  1069.         //    retrieve file infomation
  1070.         
  1071.         err = FSpGetFInfo( pFileSpec, &fileInfo );
  1072.         if ( err != noErr )
  1073.         {
  1074.             ErrorAlert( err );
  1075.             return err;
  1076.         }
  1077.         
  1078.         //    make sure we recognize the file type
  1079.     
  1080.         if ( (fileInfo.fdType != kTypeText ) && ( fileInfo.fdType != kTypeTextReadOnly ) )
  1081.         {
  1082.             err = -1;
  1083.             ErrorAlert( err );
  1084.             return err;
  1085.         }
  1086.         
  1087.         //    read in the file
  1088.         err = ReadTextFile( pFileSpec, we );
  1089.         if ( err != noErr )
  1090.         {
  1091.             ErrorAlert( err );
  1092.             return err;
  1093.         }
  1094.         
  1095.         //  you _could_ call WECalText here and recalculate the line breaks,
  1096.         //    but it's really unnecessary, and just tends to slow things down
  1097.         
  1098.         //    set the window title to the file name
  1099.         SetWTitle( window, pFileSpec->name );
  1100.         
  1101.         //    create an alias to keep track of the file
  1102.         err = NewAlias( NULL, pFileSpec, &alHandle );
  1103.         (*hDocument)->fileAlias = (Handle)alHandle;
  1104.             
  1105.         //    if the file is a read-only file (type 'ttro'), go ahead and enable
  1106.         //    those flags
  1107.         
  1108.         if (fileInfo.fdType == kTypeTextReadOnly )
  1109.             WEFeatureFlag( weFReadOnly, weBitSet, we );
  1110.         
  1111.         //    let's make sure the cursor is happy...
  1112.         InitCursor();
  1113.         
  1114.     }    // end pFileSpec != NULL
  1115.     else
  1116.         (*hDocument)->fileAlias = NULL;
  1117.  
  1118. skipit:
  1119.     
  1120.     //    adjust scroll bar settings based on the total text height
  1121.  
  1122.     AdjustBars( window );
  1123.  
  1124.     //    finally!  show the document window
  1125.  
  1126.     ShowWindow( window );
  1127.         
  1128.     return err;
  1129. }
  1130.  
  1131.  
  1132. void    DestroyWindow( WindowRef window )
  1133. {
  1134.     DocumentHandle    hDocument;
  1135.     short            menuID;
  1136.     
  1137.     hDocument = GetWindowDocument(window);
  1138.     
  1139.     //    destroy the WE record
  1140.     
  1141.     WEDispose( (*hDocument)->we );
  1142.     
  1143.     //    destory the LongControl records attached to the scroll bars
  1144.     
  1145.     LCDetach( ((*hDocument)->scrollBars).v );
  1146.     LCDetach( ((*hDocument)->scrollBars).h );
  1147.     
  1148.     //    dispose of the file alias, if any
  1149.     
  1150.     ForgetHandle( & ((*hDocument)->fileAlias) );
  1151.     
  1152.     //    destroy the window record and all associated data structures
  1153.     
  1154.     DisposeWindow( window );
  1155.     
  1156.     //    finally, dispose of the document record
  1157.     
  1158.     DisposeHandle( (Handle) hDocument );
  1159.     
  1160.     // adjust the menus to suit
  1161.     
  1162.     for ( menuID = kMenuFont; menuID <= kMenuFeatures; menuID++ )
  1163.         DisableItem( GetMenuHandle( menuID ), 0 );
  1164.     InvalMenuBar();
  1165.     
  1166.     return;
  1167. }
  1168.